package cn.ppool.xmlmapper.sql;

import cn.ppool.xmlmapper.builder.parse.model.entry.SelectBO;
import cn.ppool.xmlmapper.exctption.MulpitleResultException;
import cn.ppool.xmlmapper.exctption.MultipleColumnException;
import cn.ppool.xmlmapper.exctption.SelectNeedReturnObjectException;
import lombok.extern.log4j.Log4j2;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Log4j2
public class SelectObjectPackerServiceImpl implements SelectObjectPackerService {


    public final static Map<String, Class<?>> baseTypeToMap = new HashMap<String, Class<?>>() {{
        put("string", String.class);
        put("bool", Boolean.class);
        put("boolean", Boolean.class);
        put("int", Integer.class);
        put("integer", Integer.class);
        put("double", Double.class);
        put("float", Float.class);
        put("void", null);
    }};

    protected Class<?> getReturnClass(Type type) throws Exception {
        return baseTypeToMap.containsKey(type.getTypeName()) ? baseTypeToMap.get(type.getTypeName()) : Class.forName(type.getTypeName());
    }

    protected List<Class<?>> getReturnGenericityClass(Type type) throws Exception {
        List<Class<?>> clazzList = new ArrayList<>();
        if (type instanceof ParameterizedType) {        // 判断获取的类型是否是参数类型
            Type[] typesto = ((ParameterizedType) type).getActualTypeArguments();
            for (Type tp : typesto) {
                if (!(tp instanceof ParameterizedType)) {
                    clazzList.add(baseTypeToMap.containsKey(tp.getTypeName()) ? baseTypeToMap.get(tp.getTypeName()) : Class.forName(tp.getTypeName()));
                } else {
                    clazzList.add((Class<?>) ((ParameterizedType) tp).getRawType());
                }
            }
        }
        return clazzList;
    }


    @Override
    public Class<?> getReturnClass(SelectBO entryBO, Method method) throws Exception {
        Class<?> fx = null;
        Class<?> returnType = getReturnClass(method.getReturnType());
        List<Class<?>> returnGenericityType = getReturnGenericityClass(method.getGenericReturnType());
        if (returnType == null) throw new SelectNeedReturnObjectException("select 必须有返回");
        //
        if (returnType == List.class) {
            if (returnGenericityType.size() == 0) {
                fx = Object.class;
            } else {
                Type tt = returnGenericityType.get(0);
                fx = baseTypeToMap.containsKey(tt.getTypeName()) ? baseTypeToMap.get(tt.getTypeName()) : Class.forName(tt.getTypeName());
            }
        } else if (returnType == Map.class) {
            fx = Map.class;
        } else {
            fx = getBeanReturnClass(entryBO, method, returnType, returnGenericityType);
        }
        return fx;
    }

    public Class<?> getBeanReturnClass(SelectBO entryBO, Method method, Class<?> returnType, List<Class<?>> returnGenericityType) throws Exception {
        return (baseTypeToMap.containsKey(returnType.getTypeName()) ?
                baseTypeToMap.get(returnType.getTypeName()) :     // 基本类型
                Class.forName(returnType.getTypeName()));         // bean
    }


    @Override
    public Object resultMapPacker(SelectBO selectBO, String sql, Map<String, Object> allVar, Map<String, Object> sqlVar) {
        List<Map> sqlSucc = selectBO.getMapperBuilder().getRequestSqlService().queryToMap(sql, allVar, sqlVar);
        if (selectBO.isOnlyOne() && sqlSucc != null && sqlSucc.size() > 1) {
            throw new MulpitleResultException("select only one 返回了" + sqlSucc.size() + "个结果");
        } else if (selectBO.isOnlyOne() && sqlSucc != null) {
            Map resultMap = sqlSucc.get(0);
            if (selectBO.getResultType() == String.class || selectBO.getResultType() == Boolean.class || selectBO.getResultType() == Number.class
                    || selectBO.getResultType() == Integer.class || selectBO.getResultType() == Double.class || selectBO.getResultType() == Float.class) {
                if (resultMap.size() > 1) {
                    throw new MultipleColumnException("返回多列结果集");
                } else {
                    Map.Entry<String, Object> entry = (Map.Entry<String, Object>) sqlSucc.get(0).entrySet().iterator().next();
                    return entry.getValue();
                }
            } else {        // bean
                return resultMap;
            }
        } else {
            return sqlSucc;
        }
    }

    @Override
    public Object resultBeanPacker(SelectBO selectBO, String sql, Map<String, Object> allVar, Map<String, Object> sqlVar) {
        List<?> sqlSucc = selectBO.getMapperBuilder().getRequestSqlService().queryToBean(sql, allVar, sqlVar, selectBO.getResultType());
        if (selectBO.isOnlyOne() && sqlSucc != null && sqlSucc.size() > 1) {
            throw new MulpitleResultException("select only one 返回了" + sqlSucc.size() + "个结果");
        } else if (selectBO.isOnlyOne() && sqlSucc != null) {
            return sqlSucc.size() == 1 ? sqlSucc.get(0) : null;
        } else {
            return sqlSucc;
        }
    }


}
